package edu.whu.tao.dao;

import java.io.Serializable;
import java.util.List;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

import edu.whu.tao.constant.CommonConstants;

/**
 * 
 * <P>Hibernate通用dao</P>
 * @author 陶焕(13294175866)
 * @date 2016年4月17日 下午7:34:18
 */
@Repository("genericDao")
public class GenericDao<T extends Serializable> {

	@Resource
	private SessionFactory sessionFactory;
	
	public Session getSession() {
		return this.sessionFactory.getCurrentSession();
	}
	
	/**
	 * 
	 * <p>根据id获取实体</p>
	 * @param t
	 * @param id
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public T getByKey(Class<T> t, Serializable id) {
		return (T) getSession().get(t, id);
	}
	
	/**
	 * 
	 * <p>根据id获取实体,将已经被软删除的数据清掉</p>
	 * @param t 类
	 * @param id
	 * @param idProperty  主键属性
	 * @param stateProperty 状态属性
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public T getById(Class<T> t, Serializable id, Serializable idProperty, Serializable stateProperty) {
		DetachedCriteria detachedCriteria = DetachedCriteria.forClass(t);
		detachedCriteria.add(Restrictions.eq((String) idProperty, id)).add(
				Restrictions.ne((String) stateProperty, CommonConstants.STATE_DEL));
		List<T> list = findByCriteria(t, detachedCriteria);
		if ((list == null) || (list.isEmpty())) {
			return null;
		}
		return list.get(0);
	}
	
	/**
	 * 
	 * <p>更新实体</p>
	 * @param entity
	 * @author 陶焕(13294175866)
	 */
	public void update(T entity) {
		getSession().update(entity);
	}

	/**
	 * 
	 * <p>保存实体</p>
	 * @param entity
	 * @author 陶焕(13294175866)
	 */
	public T save(T entity) {
		return (T) getSession().save(entity);
	}

	/**
	 * 
	 * <p>硬删除实体</p>
	 * @param entity
	 * @author 陶焕(13294175866)
	 */
	public void delete(T entity) {
		getSession().delete(entity);
	}
	
	/**
	 * 
	 * <p>根据主键硬删除实体</p>
	 * @param t
	 * @param id
	 * @param idProperty
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public int deleteByKey(Class<T> t, Serializable id, Serializable idProperty) {
		return deleteByKeys(t, new Serializable[] { id }, idProperty);
	}

	/**
	 * 
	 * <p>根据主键硬删除实体</p>
	 * @param t
	 * @param ids
	 * @param idProperty
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public int deleteByKeys(Class<T> t, Serializable[] ids, Serializable idProperty) {
		if ((idProperty != null) && (ids != null)) {
			Session session = getSession();
			String strClassSimpleName = t.getSimpleName();
			strClassSimpleName = strClassSimpleName.substring(strClassSimpleName.lastIndexOf(".") + 1);
			StringBuffer sb = new StringBuffer();
			sb.append("delete ");
			sb.append(strClassSimpleName).append(" c ");
			sb.append("where ");
			sb.append("c.");
			sb.append(idProperty);
			sb.append(" in (");
			for (Serializable id : ids) {
				sb.append("'");
				sb.append(id);
				sb.append("'");
				sb.append(",");
			}
			sb.replace(sb.length() - 1, sb.length(), ")");
			Query query = session.createQuery(sb.toString());
			query.executeUpdate();
			return ids.length;
		}
		return 0;
	}
	
	/**
	 * 
	 * <p>根据主键软删除实体</p>
	 * @param t
	 * @param id
	 * @param idProperty
	 * @param stateProperty
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public int deleteSoftByKey(Class<T> t, Serializable id, Serializable idProperty, Serializable stateProperty) {
		return deleteSoftByKeys(t, new Serializable[] { id }, idProperty, stateProperty);
	}

	/**
	 * 
	 * <p>根据主键软删除实体</p>
	 * @param t
	 * @param id
	 * @param idProperty
	 * @param stateProperty
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public int deleteSoftByKeys(Class<T> t, Serializable[] ids, Serializable idProperty, Serializable stateProperty) {
		if ((idProperty != null) && (ids != null) && (stateProperty != null)) {
			Session session = getSession();
			String strClassSimpleName = t.getSimpleName();
			strClassSimpleName = strClassSimpleName.substring(strClassSimpleName.lastIndexOf(".") + 1);
			StringBuffer sb = new StringBuffer();
			sb.append("update ");
			sb.append(strClassSimpleName).append(" c ");
			sb.append("set c.");
			sb.append(stateProperty);
			sb.append("=");
			sb.append(CommonConstants.STATE_DEL);
			sb.append(" where ");
			sb.append("c.");
			sb.append(idProperty);
			sb.append(" in (");
			for (Serializable id : ids) {
				sb.append("'");
				sb.append(id);
				sb.append("'");
				sb.append(",");
			}
			sb.replace(sb.length() - 1, sb.length(), ")");
			Query query = session.createQuery(sb.toString());
			query.executeUpdate();
			return ids.length;
		}
		return 0;
	}
	
	/**
	 * 
	 * <p>批量添加和更新</p>
	 * @param entities
	 * @author 陶焕(13294175866)
	 */
	public void saveOrUpdateAll(List<T> entities) {
		Session session = getSession();
		for (int i = 0; i < entities.size(); i++) {
			session.saveOrUpdate(entities.get(i));
			if (i % CommonConstants.BATCH_COUNT == 0) {
				session.flush();
				session.clear();
			}
		}
		session.flush();
		session.clear();
	}
	
	/**
	 * 
	 * <p>查询总数</p>
	 * @param detachedCriteria
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public long count(DetachedCriteria detachedCriteria) {
		return detachedCriteria.getExecutableCriteria(getSession()).list().size();
	}
	
	/**
	 * 
	 * <p>查询所有</p>
	 * @param t
	 * @param detachedCriteria
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public List findByCriteria(Class<T> t, DetachedCriteria detachedCriteria) {
		return findByCriteria(t, detachedCriteria, 0, 0);
	}

	/**
	 * 
	 * <p>分页查询</p>
	 * @param t
	 * @param detachedCriteria
	 * @param page 当前页
	 * @param maxResults 每页的条数
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public List findByCriteria(Class<T> t, DetachedCriteria detachedCriteria,int page, int maxResults) {
		return findByCriteria(t,detachedCriteria,false,page,maxResults);
	}
	
	/**
	 * 
	 * <p>分页查询</p>
	 * @param t
	 * @param detachedCriteria
	 * @param page 当前页
	 * @param maxResults 每页的条数
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public List findByCriteria(Class<T> t, DetachedCriteria detachedCriteria,boolean useCache, int page, int maxResults) {
		if (detachedCriteria == null) {
			detachedCriteria = DetachedCriteria.forClass(t);
		}
		Criteria criteria = detachedCriteria.getExecutableCriteria(getSession());
		criteria.setCacheable(useCache);
		if (maxResults > 0) {
			page = page > 0 ? page : 1;
			int firstResult = maxResults * (page - 1);
			criteria.setFirstResult(firstResult);
			criteria.setMaxResults(maxResults);
		}
		return criteria.list();
	}
	
	/**
	 * 
	 * <p>
	 * 使用原生SQL语句查询,可调用数据库的存储过程
	 * 	SQLQuery query =  session.createSQLQuery("{call proc_stuInfo()}").addEntity(StuInfo.class);    
		List list =query.list();   
		System.out.println(list.get(0)); 
		
		SessionFactory sf = SessionFactoyUtil.getSessionFactory();  
    	Session session = sf.openSession();  
    	SQLQuery query =   session.createSQLQuery("{CALL proc_find_stu(?,?)}").addEntity(StuInfo.class);  
    	query.setLong(0, 2);    
    	query.setLong(1, 4);    
    	List<StuInfo> list =query.list();   
     		for(int i =0;i<list.size();i++){  
         	System.out.println(list.get(i));  
     	} 
	 * </p>
	 * @param t
	 * @param queryString
	 * @param params
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public List sqlQuery(Class<T> t, String queryString, Object... params) {
		return sqlQuery(t, queryString, params, 0, 0);
	}

	/**
	 * 
	 * <p>使用原生SQL语句查询</p>
	 * @param t
	 * @param queryString
	 * @param params
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public List sqlQuery(Class<T> t, String queryString, Object[] params, int pages, int maxResults) {
		return sqlQuery(t, queryString, params, false, pages, maxResults);
	}
	
	/**
	 * 
	 * <p>使用原生SQL语句查询</p>
	 * @param t
	 * @param queryString
	 * @param params
	 * @return
	 * @author 陶焕(13294175866)
	 */
	public List sqlQuery(Class<T> t, String queryString, Object[] params,boolean useCache, int pages, int maxResults) {
		Query query = getSession().createSQLQuery(queryString).addEntity(t);
		query.setCacheable(useCache);
		for (int i = 0; i < params.length; i++) {
			query.setParameter(i, params[i]);
		}
		if (maxResults > 0) {
			pages = pages > 0 ? pages : 1;
			int firstResult = maxResults * (pages - 1);
			query.setFirstResult(firstResult);
			query.setMaxResults(maxResults);
		}
		return query.list();
	}
	
	
	public int updateBySql(String updateSql, Object... params) {
		Query query = getSession().createSQLQuery(updateSql);
		for (int i = 0; i < params.length; i++) {
			query.setParameter(i, params[i]);
		}
		return query.executeUpdate();
	}

	public int updateBySql(String updateSql, String[] paramNames, Object... params) {
		Query query = getSession().createSQLQuery(updateSql);
		for (int i = 0; i < params.length; i++) {
			query.setParameter(paramNames[i], params[i]);
		}
		return query.executeUpdate();
	}
	
	
}
